/*
 * To change this template, choose Tools | Templates
 * and open the template in the editor.
 */
package evotingclient.model;

import java.io.BufferedReader;
import java.io.File;
import java.io.FileNotFoundException;
import java.io.IOException;
import java.io.InputStream;
import java.io.InputStreamReader;
import java.io.OutputStream;

/**
 *
 * @author Maciek
 */
public class CertificateManager {
    
    
    public static String keystore = "evotingKeyStore.jks";
    private static String pkw = "PKW";
    private String nick;
    private String keypass;
    private String path;
    private String storepass;
    
    public static int FileAllreadyExists = 4;
    
    
    public CertificateManager(String nick, String password, String path) {
        this.nick = nick;
        this.keypass = password;
        this.path = path;
        storepass = password;
    }
    
     public int exportKeyToFile() throws IOException, InterruptedException{
        String keyPath = getPath(nick + ".cer");
        File file = new File(keyPath);
        if(file.exists())
            return CertificateManager.FileAllreadyExists; 
        return this.exportKeyCommand(nick,keyPath);
    }
     
     public int exportSignReqToFile() throws IOException, InterruptedException{
         String keyPath = getPath(nick + ".csr");
         File file = new File(keyPath);
         if(file.exists())
            return CertificateManager.FileAllreadyExists; 
        return this.certreqKeyCommand(nick,keyPath);
     }
    public int generateCertificate(PersonalData pd) throws IOException, InterruptedException{
         return generateKeyCommand(nick, pd);
    }
    
    public int trustPKWCertificate() throws IOException, InterruptedException{
        String pkwCertificatePath = getPath(pkw + ".cer");
        System.out.println(pkwCertificatePath);
        File file = new File(pkwCertificatePath);
        if(!file.exists()){
            throw new FileNotFoundException(file.getAbsolutePath());
        }
            
        return importCert(pkw,pkwCertificatePath);
    }
    
    
    
    public int importSignedCertificate() throws FileNotFoundException, IOException, InterruptedException{
        String signedCertificate = getPath(nick + "_signed.cer");
         File file = new File(signedCertificate);
         if(!file.exists()){
            throw new FileNotFoundException(file.getAbsolutePath());
         }
         
         return importCert(nick,signedCertificate);
    }
    public String getPath(String name){
        StringBuilder mpath= new StringBuilder();
        if(!path.equals(""))
            mpath.append(path).append(File.separator);
         
         mpath.append(nick);
         if(!name.equals("")){
             mpath.append(File.separator);        
             mpath.append(name);
         }
        return mpath.toString();
    }
    private String buildImportCommand(String alias, String certfilepath){
        StringBuilder command = new StringBuilder();
        command.append("cmd.exe /c keytool -import -alias ");
        command.append(alias);
        command.append(" -file ").append(certfilepath);
        command.append(" -keystore ").append(getPath(keystore));
        command.append(" -storepass ").append(storepass);
        return command.toString();
    }
    
    private int importCert(String alias, String certfilepath) throws IOException, InterruptedException{
      OutputStream stdin = null; 
      //Process process = Runtime.getRuntime().exec ("cmd.exe /c keytool -import -alias maciej -file maciej.cer -keystore mastakeystore.jks -storepass bskbsk");
      Process process = Runtime.getRuntime().exec(buildImportCommand(alias,certfilepath));
      stdin = process.getOutputStream (); // przechwytuje wejscia wyjscia
      stdin.write("yes\n".getBytes()); // potwierdzam, że temu certyfikatowi wierze
      stdin.flush();
      stdin.close();
      getInput(process); 
      if(process.waitFor() == 0) {
            String command = buildExportKeystoreCommand(alias);
            process = Runtime.getRuntime().exec(command);
            getInput(process);
            return process.waitFor();
        }
      return -1;
      
    }
    
    private String dName(PersonalData pd){
        StringBuilder sb = new StringBuilder();
        sb.append('\"');
        sb.append("CN=").append(pd.firstName);
        sb.append(" ").append(pd.lastName);
        sb.append(" ").append(pd.Pesel);
        sb.append(",O=").append("PKW");
        sb.append(",C=").append("PL");
        sb.append('\"');
        return sb.toString();
    }
    
    private String buildGenerateKeyCommand(String alias, PersonalData pd){
        
        StringBuilder sb = new StringBuilder();
        sb.append("cmd.exe /c keytool -keyalg RSA -alias ").append(alias);// odpalając bez start
        // nie otworzy nam się okno i wtedy będzie miało sens przechwytywanie strumieni
        sb.append(" -genkey -storepass ").append(storepass);
        sb.append(" -keystore ").append(getPath(keystore));
        sb.append(" -keypass ").append(keypass);
        sb.append(" -dname ").append(dName(pd));
        return sb.toString();
    }
    
    private String buildExportKeystoreCommand(String alias) {
        StringBuilder sb = new StringBuilder();
        sb.append("keytool -importkeystore -srckeystore ").append(getPath(keystore));
        sb.append(" -destkeystore ").append(getPath(keystore).replace(".jks", ".p12"));
        sb.append(" -srcstoretype JKS -deststoretype PKCS12 -srcstorepass ");
        sb.append(keypass).append(" -deststorepass ").append(keypass);
        sb.append(" -srcalias ").append(alias).append(" -destalias ").append(alias);
        sb.append(" -srckeypass ").append(keypass);
        sb.append(" -destkeypass ").append(keypass).append(" -noprompt ");
        return sb.toString();
    }
    
   
    
     private int generateKeyCommand(String alias, PersonalData pd) throws IOException, InterruptedException{
        String command = buildGenerateKeyCommand(alias,pd);
        System.out.println("Generowanie klucz : " + command);
        Process proc = Runtime.getRuntime().exec(command);
        getInput(proc); // wypisuje wszystko co otrzymam z odpowiedniego miejsca
        return proc.waitFor();
    }
     
     private  String buildExportKeyCommand(String alias, String certfilepath) {
        StringBuilder sb = new StringBuilder();
        sb.append("cmd.exe /c keytool -export -alias ").append(alias); // odpalając bez start
        // nie otworzy nam się okno i wtedy będzie miało sens przechwytywanie strumieni
        sb.append(" -keystore ").append(getPath(keystore));
        sb.append(" -file ").append(certfilepath);
        sb.append(" -storepass ").append(storepass);
        // sb.append(" -rfc "); jeśli byśmy chcieli żeby to było później czytelne 
        return sb.toString();
    } 
     
    private String buildcertreqKeyCommand(String alias, String certfilepath){
        StringBuilder sb = new StringBuilder();
        sb.append("cmd.exe /c keytool -certreq -alias ").append(alias);
        sb.append(" -keystore ").append(getPath(keystore));
        sb.append(" -file ").append(certfilepath);
        sb.append(" -storepass ").append(storepass);
        sb.append(" -keypass ").append(keypass);
        return sb.toString();
    }
    
    private int certreqKeyCommand(String alias, String certfilepath) throws IOException, InterruptedException{
        String command = buildcertreqKeyCommand(alias,certfilepath);
        System.out.println("Signrequest command " + command);
        Process proc = Runtime.getRuntime().exec(command);
        getInput(proc); // wypisuje wszystko co otrzymam z odpowiedniego miejsca
        return proc.waitFor();
    }
    private int exportKeyCommand(String alias, String certfilepath) throws IOException, InterruptedException{
        String command = buildExportKeyCommand(alias,certfilepath);
        System.out.println("Eksportowanie klucza " + command);
        Process proc = Runtime.getRuntime().exec(command);
        getInput(proc); // wypisuje wszystko co otrzymam z odpowiedniego miejsca
        return proc.waitFor();
    }
    private static void getInput(Process proc) throws IOException{ // tu pożnaby zapisywać do jakiś plików
         InputStream stdout = proc.getInputStream();
        String line;
        InputStream stderr = proc.getErrorStream();
          BufferedReader brCleanUp =
        new BufferedReader (new InputStreamReader (stdout));
        
          while ((line = brCleanUp.readLine ()) != null) {
            System.out.println ("[Stdout] " + line);
          }
          brCleanUp.close();

          // clean up if any output in stderr
          brCleanUp =
            new BufferedReader (new InputStreamReader (stderr));
          while ((line = brCleanUp.readLine ()) != null) {
            System.out.println ("[Stderr] " + line);
          }
          brCleanUp.close();
    } 
    
   
}
